<?php
	namespace App\Http\Middleware;

	use Closure;
	use Illuminate\Http\Request;
	use Illuminate\Support\Facades\Route;
	use App\Func\ResponseFunc;
	use App\Consts\ResponseConsts\ResponseStatusConsts;
	use App\Func\RequestFunc;

	/* PHP run environment run time maximum memory limit adjust
	 *
	 */
	ini_set('memory_limit', '128M');

	/* developer	: BREEZEER
	 * date			: 2022/6/23
	 * description	: 
	 *					1. 用户访问 API 必须携带[ user_token ]
	 *					2. 过滤出需要权限效验的 route method
	 *					3. 读取当前访问 method 对应 controller 的数据位权限要求 
	 *					4. 通过 user_id 获取用户的权限列表，验证权限列表是否满足 3 的要求满足放行
	 *						4.1 鉴权失败返回 401 code [@2022.11.10]

	 *					5. 权限校验的前置条件
	 *						5.1 用户必须登录
	 *						5.2 用户必须拥有服务器下发的 token
	 *						5.3 用户登录会话校验包括且不限于
	 *							5.3.1 是否登录
	 *							5.3.2 登录会话是否过期
	 *	 							
	 *	 							
	 *	 							
	 *	 							
	 */
	class c_middleware_verify_user_visit_permission
	{
		public function __construct	()
		{	
			$this->m_cHelper			= app()->gcHelper						; 
			$this->m_redis              = $this->m_cHelper->gfGetRedis()		;

		}

		/* 检查当前正在访问的路由控制器方法否要被做权限校验
		 *
		 *
		 *
		 *
		 *
		 */
		private function currentPathMatchRouteMethodUri($current_path/* 正在访问的路由方法路径 */,$route_method_uri/* 框架内完整的路由uri */,$route_controller/* 框架内完整的控制器路由方法 */)
        {
			# 正在访问的路由控制器方法如果匹配框架内完整的控制器路由方法 [ App\Http\Controllers\staffPermission\cStaffPermissionController@createRoleName ] 
			#
			if(Route::getCurrentRoute()->getActionName() == $route_controller)
			{
				return true;	# 此路由方法需要权限限制
			}
			else
			{
				return false;	# 不需要权限随便访问吧骚年
			}
			
			//			# 利用正则表达式进行非贪婪模糊匹配
			//			#
			//			$route_method_uri_to_pcre_mode = '/'.preg_replace(['/{.*}/U','/\/\//','/\//'],['(.*)','/','\/'],$route_method_uri).'/U';if(preg_match($route_method_uri_to_pcre_mode,$current_path) >0 )
			//			{
			//				return true;
			//			}
		}

		/* 通过路由方法验证当前用户的数据访问权限	=> data permission [ 32位长度的权限值，每一个比特位置0|1都是开关， 0禁用 1启用，1=read 2=write 4=modify 8=delete ，权限位可以或与操作 ]
		 *
		 *
		 *
		 *
		 */
		private function verfiyRoutePermission($current_path,$user_id)
		{
			# get all route method then filter i will need verify method only 
			#
			#
			$all_route_uri					= [];
            foreach(Route::getRoutes()->get() as $one_route)
			{
				$ooo						= (object)$one_route	;

				# 通过路由文件的uri前缀过滤出需要处理的路由方法
				#
				#
				$route_prefix			    = @explode('/',$ooo->uri)[0].'/';if(in_array($route_prefix,['api/']))
				{
					if($this->currentPathMatchRouteMethodUri($current_path,$ooo->uri,$ooo->action['controller']))
					{
						# 正在访问的路由方法需要权限验证
						#
						$controller			= explode('@',$ooo->action['controller']);
						$all_route_uri []	= [	
													'uri'				=> @$ooo->uri		,	# controller full uri address
													'controller_class'	=> @$controller[0]	,	# controller class full namespace 
													'controller_method'	=> @$controller[1]	,	# controller method
											  ];
					}
				}
			}
            
            # 当前访问的url地址没有找到匹配的路由方法直接放行
            #
            if(count($all_route_uri)==0)
            {
                return true;
            }            
			
			# permission check
			#
			#
			foreach($all_route_uri as $k => $one_route_method)
			{
				$one_route_method_ooo			= (object)$one_route_method	;
				$one_route_method_ooo->user_id	= $user_id					;

				# create route controller instance by full namespace and check data permission
				#
				#
				$controller_instance			= new $one_route_method_ooo->controller_class;if(method_exists($controller_instance,'permissionCheck')/* 路由方法有权限限定要求 */ && $user_id>0 /* 职员id > 0 */)
				{
					if($controller_instance->permissionCheck($one_route_method_ooo))
					{
					}
					else
					{
						# 这一组路由接口当中有一个验证失败,立即断言这次访问验证失败
						#
						return false;
					}
				}
				else
				{
						# 路由方法没有权限限定直接放行 go .... 
						#
				}
			}

			return true;
		}

		/**
		 * Handle an incoming request.
		 *
		 * @param  \Illuminate\Http\Request  $request
		 * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
		 * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
		 *
		 *
		 *
		 *
		 *
		 *
		 *
		 */
		public function handle(Request $request, Closure $next)
		{
			# 客户端访问服务器必须携带的验证参数
			#
			# tips	:
			#
			#			1. user_id		= 11																													# 后台职员登录后的id
			#			2. user_token	= xxxxxxxxxxxx																											# 后台职员登录后，服务器返回给客户端的token，客户端访问url必须再次携带 token 待服务器验证
			#
			#
			#
			$this->m_helper				= app()->gcHelper																									;	# gcHelper object
			$user_id_and_token			= $this->m_cHelper->toObjectEx	(
																			[
																				'user_id'		=> $this->m_cHelper->gfGetCurrentStaffInfo()->staff_id			# user id	[ 这里的用户id就是后台登录的职员id ]
																				,
																				'user_token'	=> $this->m_cHelper->gfGetValueFromHeader("Transfer-Toc-V2")	# user token get from client header response
																			]
																		)																					;
			$current_path				= $request->getPathInfo()																							;	# current path information
			$user_id					= $user_id_and_token->user_id		?? 0																			;	# user id
			$user_token					= $user_id_and_token->user_token	?? ''																			;	# user token
			$ar_verify_info				= array()																											;

			# verify user visit permission
			#
			if($this->verifyUserVisitPermission($current_path,$user_id,$user_token,$ar_verify_info)) 
			{
				if($this->verfiyRoutePermission($current_path,$user_id)===false)
				{
					return	$this->m_helper->gfApiEchoExHttpExceptionByCode401("拒绝访问 : [$current_path]",'800.2005.verfiyRoutePermission');
				}

				# ok	=> allow 
				#
				return $next($request);
			} 
			else
			{
				# fail	=> reject visit when user session have expired
				#
				return	$this->m_helper->gfApiEchoExHttpExceptionByCode401("拒绝访问 : [$current_path]",'800.2004.verifyUserVisitPermission');
			}
		}

		/* @return bool value $b_visit 
		 *                              => true     : permission ok
		 *                              => false    : fail reject visit     
		 *
		 *
		 */
		private function verifyUserVisitPermission($current_path,$user_id,$user_token,&$ar_verify_info=null)
		{
			# 是否开启单点登录校验 true => 不用校验 ,false 单点校验失败
			#
			# tips
			#		1. 开启单点登录校验屏蔽此行
			#
			#
			#
			 return true;

			if($user_id==0/* 职员还没有登录禁止单点校验 */)
			{
				return  true;
			}
			else
			{
			}

			# default visit permission rejected
			#
			$b_visit            = false;
			
			# whitelist => allow visit url
			#
			$ar_allow_url       = array (  
											'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'	,
										);
			
			# current path can be visited ?
			#
			if(in_array($current_path,$ar_allow_url))
			{
				$b_visit        = true;
			}
			else
			{
				# verify ...
				#
				$b_visit        = $this->m_cHelper->gfVerifyUserTokenOK($user_id,$user_token);
			}

			#
			#
			return $b_visit;  
		}
	}
